package ppt

import (
	"bytes"
	"context"
	"strings"
	v1 "web-ppt/api/ppt/v1"
	"web-ppt/internal/dao"
	"web-ppt/internal/model/do"

	"github.com/gogf/gf/v2/database/gdb"
	"golang.org/x/net/html"
)

type PPt struct{}

func New() *PPt {
	return &PPt{}
}

func (p *PPt) List(ctx context.Context, page, size int) (r gdb.Result, count int, err error) {
	r, count, err = dao.PptTages.Ctx(ctx).Order("order desc").Page(page, size).AllAndCount(false)
	return
}

func (p *PPt) AllList(ctx context.Context) (r gdb.Result, err error) {
	r, err = dao.PptTages.Ctx(ctx).Order("order desc").All()
	return
}

func (p *PPt) Delete(ctx context.Context, id int) error {
	_, err := dao.PptTages.Ctx(ctx).Where("id", id).Delete()
	return err
}

func (p *PPt) Save(ctx context.Context, in *v1.AddAndUpdateReq) error {
	var data do.PptTages
	if in.Id == 0 {
		data = do.PptTages{
			Name:  in.Name,
			Order: in.Order,
		}
	} else {
		data = do.PptTages{
			Id:    in.Id,
			Name:  in.Name,
			Order: in.Order,
		}
	}
	_, err := dao.PptTages.Ctx(ctx).Data(data).OnConflict("id").Save()
	return err
}

func (p *PPt) ContentList(ctx context.Context, tid, page, size int) (r gdb.Result, count int, err error) {
	r, count, err = dao.Pptcontent.Ctx(ctx).Where("tags", tid).Order("tags", "order").Page(page, size).AllAndCount(false)
	return
}

func (p *PPt) ContentSave(ctx context.Context, in *v1.ContentAddAndUpdateReq) error {
	content := strings.Replace(in.Content, "</html>", "", -1)
	content = strings.Replace(content, "</body>", "", -1)
	var data do.Pptcontent
	if in.Id == 0 {
		data = do.Pptcontent{
			Name:    in.Name,
			Content: content,
			Tags:    in.Tags,
			Order:   in.Order,
		}
	} else {
		data = do.Pptcontent{
			Id:      in.Id,
			Name:    in.Name,
			Content: content,
			Tags:    in.Tags,
			Order:   in.Order,
		}
	}
	_, err := dao.Pptcontent.Ctx(ctx).Data(data).OnConflict("id").Save()
	return err
}

func (p *PPt) ContentDelete(ctx context.Context, id int) error {
	_, err := dao.Pptcontent.Ctx(ctx).Where("id", id).Delete()
	return err
}

func (p *PPt) Show(ctx context.Context, id, page int) (r gdb.Result, count int, err error) {
	r, count, err = dao.Pptcontent.Ctx(ctx).Where("tags", id).Fields("content").Order("order").Page(page, 1).AllAndCount(false)
	return
}

// 启用ppt页面上class或者id的点击功能
func (p *PPt) ListDianji(ctx context.Context) (r gdb.Result, err error) {
	r, err = dao.PptDianjigongnen.Ctx(ctx).All()
	return
}

func (p *PPt) DeleteDianji(ctx context.Context, id int) error {
	_, err := dao.PptDianjigongnen.Ctx(ctx).Where("id", id).Delete()
	return err
}

func (p *PPt) SaveDianji(ctx context.Context, in *v1.SaveDianjiReq) error {
	var data do.PptDianjigongnen
	if in.Id == 0 {
		data = do.PptDianjigongnen{
			ClassORid: in.ClassORid,
		}
	} else {
		data = do.PptDianjigongnen{
			Id:        in.Id,
			ClassORid: in.ClassORid,
		}
	}
	_, err := dao.PptDianjigongnen.Ctx(ctx).Data(data).OnConflict("id").Save()
	return err
}

// 替换网页中的资源（css、js）
func (p *PPt) ToReplace(htmlContent *string) (err error) {
	doc, err := html.Parse(strings.NewReader(*htmlContent))
	if err != nil {
		return
	}

	p.replaceResources(doc)

	var buf bytes.Buffer
	if err = html.Render(&buf, doc); err != nil {
		return
	}

	*htmlContent = buf.String()
	return
}

func (p *PPt) replaceResources(n *html.Node) {
	if n.Type == html.ElementNode {
		switch n.Data {
		case "link":
			// href := ""
			rel := ""
			for _, attr := range n.Attr {
				// if attr.Key == "href" {
				// 	href = attr.Val
				// }
				if attr.Key == "rel" {
					rel = attr.Val
				}
			}

			if rel == "stylesheet" {
				for i, attr := range n.Attr {
					if attr.Key == "href" {
						if strings.Contains(attr.Val, "bootstrap") &&
							(strings.HasSuffix(attr.Val, ".css") ||
								strings.Contains(attr.Val, "bootstrap.min.css")) {
							n.Attr[i].Val = "/resource/bootstrap-5.3.7/css/bootstrap.min.css"
						}
						if strings.Contains(attr.Val, "font-awesome") ||
							strings.Contains(attr.Val, "fontawesome") {
							n.Attr[i].Val = "/resource/fontawesome-free-7.0.0/css/all.min.css"
						}
					}
				}
			}

		case "script":
			for i, attr := range n.Attr {
				if attr.Key == "src" &&
					strings.Contains(attr.Val, "bootstrap") &&
					strings.HasSuffix(attr.Val, ".js") {
					n.Attr[i].Val = "/resource/bootstrap-5.3.7/js/bootstrap.bundle.min.js"
				}
			}
		}
	}

	for c := n.FirstChild; c != nil; c = c.NextSibling {
		p.replaceResources(c)
	}
}

// 删除textarea标签
func (p *PPt) RemoveTextareaParser(htmlStr *string) (err error) {
	// 解析HTML
	doc, err := html.Parse(strings.NewReader(*htmlStr))
	if err != nil {
		return err
	}

	// 递归删除textarea节点
	var removeNodes []*html.Node
	var traverse func(*html.Node)
	traverse = func(n *html.Node) {
		if n.Type == html.ElementNode && n.Data == "textarea" {
			removeNodes = append(removeNodes, n)
		}
		for c := n.FirstChild; c != nil; c = c.NextSibling {
			traverse(c)
		}
	}
	traverse(doc)

	// 执行删除
	for _, node := range removeNodes {
		if node.Parent != nil {
			node.Parent.RemoveChild(node)
		}
	}

	// 重新渲染HTML
	buf := new(bytes.Buffer)
	html.Render(buf, doc)
	*htmlStr = buf.String()
	return
}
